package jmm;

import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * volatile关键字测试
 *
 * @author codefish
 * @version 1.0.0
 * @since 2022/08/09 下午 04:24
 */
public class VolatileTest {
    @Test
    public void myCompute() {
        int x = 10; // L1
        int y = 5;// L2
        x = x + 5;// L3
        y = x * x;// L4
    }

    final ReentrantLock lock = new ReentrantLock();

    public void function() {
        //获取锁
        lock.lock();
        try {
            //do something...
        } finally {
            //释放锁
            lock.unlock();
        }

        //do something...

        //再次获取锁，获取锁之前必须保证锁被释放，也就是 lock.unlock()必须在 lock.lock()之前执行
        lock.lock();
        try {
            //do something...
        } finally {
            lock.unlock();
        }

    }

    @Test
    public void threadStart() {
        Thread t1 = new Thread(() -> {
            //线程run方法后执行
            System.out.println("------t1 开始 ------");
        }, "t1");

        //start方法先执行
        t1.start();
    }

    @Test
    public void threadInterrupt() {
        Thread t1 = new Thread(() -> {
            System.out.println("------t1 开始 ------");
            //interrupt方法一定先于isInterrupted()发生，以下两行代码不会被重排序
            Thread.currentThread().interrupt();
            System.out.println("线程被中断：" + Thread.currentThread().isInterrupted());
            //------------------

        }, "t1");

        t1.start();
    }

    @Test
    public void threadIsAlive() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("------t1 开始 ------");
            //interrupt方法一定先于isInterrupted()发生，以下两行代码不会被重排序
            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //------------------

        }, "t1");

        t1.start();
        t1.join();
        System.out.println("线程还在运行：" + t1.isAlive());
    }


    /**
     * 测试volatile的可见性
     */
    volatile boolean flag = true;

    @Test
    public void testVolatile() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("t1 in-----");
            while (flag) {

            }
            System.out.println("t1 out----");
        }, "t1");
        t1.start();
        try {
            TimeUnit.MILLISECONDS.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = false;
        System.out.println("main flag is:" + flag);

        t1.join();
    }


    /**
     * volatile没有原子性。。。
     */
    private static class Counter {
        volatile int val = 0;

        public int increment() {
            return ++val;
        }

        public int get() {
            return val;
        }
    }


    @Test
    public void testNoAtomic() {
        Counter counter = new Counter();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    counter.increment();
                }
            }).start();
        }
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(counter.get());
    }


    /**
     * volatile禁止指令重拍序示例
     */
    volatile boolean flag1 = false;
    int i = 0;

    public void read() {
        if (flag1) {
            System.out.println("i=" + i);

        }
    }

    public void write() {
        //普通写
        i = 2;
        //-----StoreStore-----
        //volatile写
        flag1 = true;
        //-----StoreLoad-----
    }

    @Test
    public void testNoReorder() {

    }

}
